#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# Copyright Huawei Technologies Co., Ltd. 2023-2050. All rights reserved.
"""
调用github-api完成一些批量重复性的操作
"""

import json
import os
import re
import stat
import requests
from functools import wraps
import logging as log
from typing import List

OS_FLAG = os.O_WRONLY | os.O_CREAT
STATE_FLAG = stat.S_IWUSR | stat.S_IRUSR
this_dir = os.path.dirname(os.path.abspath(__file__))
requests.packages.urllib3.disable_warnings()  # 关闭ssl证书告警
LOG_FORMAT = "%(asctime)s %(levelname)s %(funcName)s %(message)s"
DATE_FORMAT = "%Y-%m-%d %H:%M:%S"
log.basicConfig(level=log.INFO, format=LOG_FORMAT, datefmt=DATE_FORMAT)


class GitHub:
    private_token = os.getenv("private_token", "xxxxxxxxxxxxxxxxxxxxxxxxx")
    prefix = "https://github.com/api/v4"
    headers = {"PRIVATE-TOKEN": f"{private_token}"}

    def get_project_name(self, projectid: int) -> str:
        """返回仓库名"""
        postfix = f"/projects/{projectid}"
        api_url = self.prefix + postfix
        respon = requests.get(api_url, headers=self.headers, verify=False)
        respon_obj = json.loads(respon.content.decode())
        if respon.ok:
            return respon_obj["name"]
        else:
            raise Exception(f"{respon_obj}")

    def print_error_info(func):
        @wraps(func)
        def print_error_info(self, *args, **kwargs):
            bool1, bool2, info, id = func(self, *args, **kwargs)
            if bool1 and not bool2:
                log.error("ProjectID: %s, ProjectName:%s, response: \n%s", id, self.get_project_name(id), info)

        return print_error_info

    @print_error_info
    def delete_branch(self, projectid: int, branch: str, PrintErrorLog: bool = False):
        """删除仓库的分支"""
        postfix = f"/projects/{projectid}/repository/branches/{branch}"
        api_url = self.prefix + postfix
        respon = requests.delete(api_url, headers=self.headers, verify=False)
        respon_obj = respon.text
        return PrintErrorLog, respon.ok, respon_obj, projectid

    @print_error_info
    def delete_tag(self, projectid: int, tag_name: str, PrintErrorLog: bool = False):
        """删除仓库的tag"""
        postfix = f"/projects/{projectid}/repository/tags/{tag_name}"
        api_url = self.prefix + postfix
        respon = requests.delete(api_url, headers=self.headers, verify=False)
        respon_obj = respon.text  # 这里没有返回值,用jsonloads会报错
        return PrintErrorLog, respon.ok, respon_obj, projectid

    @print_error_info
    def delete_branch_protect(self, projectid: int, branch: str, PrintErrorLog: bool = False):
        """删除仓库的保护分支"""
        postfix = f"/projects/{projectid}/protected_branches/{branch}"
        api_url = self.prefix + postfix
        respon = requests.delete(api_url, headers=self.headers, verify=False)
        respon_obj = respon.text  # 这里没有返回值,用jsonloads会报错
        return PrintErrorLog, respon.ok, respon_obj, projectid

    @print_error_info
    def delete_tag_protect(self, projectid: int, tag_name: str, PrintErrorLog: bool = False):
        """删除仓库的tag保护"""
        postfix = f"/projects/{projectid}/protected_tags/{tag_name}"
        api_url = self.prefix + postfix
        respon = requests.delete(api_url, headers=self.headers, verify=False)
        respon_obj = respon.text
        return PrintErrorLog, respon.ok, respon_obj, projectid

    @print_error_info
    def add_branch(self, projectid: int, branch: str, ref: str, PrintErrorLog: bool = False):
        """仓库拉分支"""
        postfix = f"/projects/{projectid}/repository/branches"
        api_url = self.prefix + postfix
        data = {"branch": branch, "ref": ref}
        respon = requests.post(api_url, headers=self.headers, data=json.dumps(data), verify=False)
        respon_obj = json.loads(respon.content.decode())
        return PrintErrorLog, respon.ok, respon_obj, projectid

    @print_error_info
    def add_branch_protect(self, projectid: int, branch: str, PrintErrorLog: bool = False):
        """仓库设保护分支"""
        postfix = f"/projects/{projectid}/protected_branches"
        api_url = self.prefix + postfix
        data = {"name": branch, "access_level_string": {"merge_access_levels": "35", "push_access_levels": ""}}
        respon = requests.post(api_url, headers=self.headers, data=json.dumps(data), verify=False)
        respon_obj = json.loads(respon.content.decode())
        return PrintErrorLog, respon.ok, respon_obj, projectid

    @print_error_info
    def add_tag(self, projectid: int, tag_name: str, ref: str, PrintErrorLog: bool = False):
        """仓库拉tag"""
        postfix = f"/projects/{projectid}/repository/tags"
        api_url = self.prefix + postfix
        data = {"tag_name": tag_name, "ref": ref}
        respon = requests.post(api_url, headers=self.headers, data=json.dumps(data), verify=False)
        respon_obj = json.loads(respon.content.decode())
        return PrintErrorLog, respon.ok, respon_obj, projectid

    @print_error_info
    def add_tag_protect(self, projectid: int, tag_name: str, PrintErrorLog: bool = False):
        """仓库设保护tag"""
        postfix = f"/projects/{projectid}/protected_tags"
        api_url = self.prefix + postfix
        data = {"name": tag_name, "create_access_level": "35"}
        respon = requests.post(api_url, headers=self.headers, data=json.dumps(data), verify=False)
        respon_obj = json.loads(respon.content.decode())
        return PrintErrorLog, respon.ok, respon_obj, projectid

    @print_error_info
    def add_e2e_domain_name(self, projectid: int, domain_name: str, PrintErrorLog: bool = False):
        """添加e2e需求空间(域名)"""
        postfix = f"/projects/{projectid}/cloud_alm/add_domain"
        api_url = self.prefix + postfix
        data = {"add_domain": domain_name, "is_used_domain": "1"}
        respon = requests.post(api_url, headers=self.headers, data=json.dumps(data), verify=False)
        respon_obj = json.loads(respon.content.decode())
        return PrintErrorLog, respon.ok, respon_obj, projectid

    @print_error_info
    def list_pbi_name(self, projectid: int, PrintErrorLog: bool = False):
        """查看pbi列表信息"""
        postfix = f"/projects/{projectid}/pbis?per_page=100"
        api_url = self.prefix + postfix
        respon = requests.get(api_url, headers=self.headers, verify=False)
        respon_obj = json.loads(respon.content.decode())
        log.info(respon_obj)

    @print_error_info
    def add_pbi_name(
        self,
        projectid: int,
        pi_id: int,
        pi_name: str,
        pp_id: int,
        pp_name: str,
        pr_id: str,
        pr_name: str,
        pc_id: str,
        pc_name: str,
        cmo_name: str,
        pbi_type: int,
        PrintErrorLog: bool = False,
    ):
        """添加pbi"""
        postfix = f"/projects/{projectid}/pbis"
        api_url = self.prefix + postfix
        data = {
            "pi_id": pi_id,
            "pi_name": pi_name,
            "pp_id": pp_id,
            "pp_name": pp_name,
            "pr_id": pr_id,
            "pr_name": pr_name,
            "pc_id": pc_id,
            "pc_name": pc_name,
            "cmo_name": cmo_name,
            "pbi_type": pbi_type,
        }
        respon = requests.post(api_url, headers=self.headers, data=json.dumps(data), verify=False)
        respon_obj = json.loads(respon.content.decode())
        respon_obj = json.loads(respon.content.decode())
        return PrintErrorLog, respon.ok, respon_obj, projectid

    def app_list_all_groups(self, top_groupid: str):
        groups_list = []

        def list_all_groups(group_id):
            """递归获取组织和组织下所有组织id"""
            getsub_url = self.prefix + f"/groups/{group_id}/subgroups"
            respon = requests.get(getsub_url, headers=self.headers, verify=False)
            respon_obj = json.loads(respon.content.decode())
            if len(respon_obj) != 0:
                for g in respon_obj:
                    groups_list.append(g["id"])
                    list_all_groups(g["id"])

        list_all_groups(top_groupid)

        try:
            groups_list.remove(484527) 
        except Exception:
            log.info("此产品下不存在组织名xxxxxxxxxxxxxxxxxxxx")
        # 如果groups_list返回的为空，也就是没有子组织,这时的group_list = [top_groupid]
        if not groups_list:
            groups_list = [top_groupid]
        return groups_list

    def get_project_infomation(self, top_groupid: str) -> List[int]:
        """得到组织下所有的项目信息: id、url、name; 返回一个它们组成的三元组"""
        projects_list = []
        # 先获取所有子组织
        groups_list = self.app_list_all_groups(top_groupid)
        # Start..................
        for g in groups_list:
            getpro_url = self.prefix + f"/groups/{g}/projects?page=1&per_page=100"
            respon = requests.get(getpro_url, headers=self.headers, verify=False)
            if len(respon.text) != 0:
                respon_obj = json.loads(respon.content.decode())
                for p in respon_obj:
                    t = (p["id"], p["name"], p["http_url_to_repo"])
                    projects_list.append(str(t))
        projects_file = os.path.join(this_dir, "..", "..", "target\\project_infomation.txt")
        if not os.path.exists(os.path.dirname(projects_file)):
            os.makedirs(os.path.dirname(projects_file))
        # 把project_id写入文件
        with os.fdopen(os.open(projects_file, OS_FLAG, STATE_FLAG), "w") as fw:
            fw.write(str(projects_list) + "\n")
            log.info("json:success")
        return projects_list

    def get_all_projectid(self, top_groupid: str, keyword: str = "id") -> List[int]:
        """递归获取组织下所有项目id,也可以通过传参获取项目其他信息"""
        projects_list = []
        # 先获取所有子组织
        groups_list = self.app_list_all_groups(top_groupid)
        # 根据组织获取所有项目
        for g in groups_list:
            getpro_url = self.prefix + f"/groups/{g}/projects?page=1&per_page=100"
            respon = requests.get(getpro_url, headers=self.headers, verify=False)

            if len(respon.text) != 0:
                respon_obj = json.loads(respon.content.decode())
                for p in respon_obj:
                    projects_list.append(p[keyword])

        # 把project_id写入文件
        projects_file = os.path.join(this_dir, "projects_id")
        with os.fdopen(os.open(projects_file, OS_FLAG, STATE_FLAG), "w") as fw:
            fw.seek(0)
            fw.truncate()
            fw.write(str(projects_list))
            log.info("json:success")
        return projects_list

    def get_all_httpurl_and_path(self, top_groupid: str) -> List[int]:
        """top_groupid:顶层组织id,通过顶层组织id递归获取仓库url和path,返回嵌套列表"""
        projects_list = []
        # 先获取所有子组织
        groups_list = self.app_list_all_groups(top_groupid)
        # 根据组织获取所有项目
        for g in groups_list:
            getpro_url = self.prefix + f"/groups/{g}/projects?page=1&per_page=100"
            respon = requests.get(getpro_url, headers=self.headers, verify=False)
            if len(respon.text) != 0:
                respon_obj = json.loads(respon.content.decode())
                for p in respon_obj:
                    list_tmp = []
                    list_tmp.append(p["http_url_to_repo"])
                    list_tmp.append(re.sub(" ", "", p["name_with_namespace"]))
                    projects_list.append(list_tmp)
        return projects_list

    def get_required_reviewers(self, projectid: int) -> List[str]:
        """获取合并请求设置的必选评审人,适用于只有一个规则情形"""
        required_reviewers = []
        postfix = f"/projects/{projectid}/merge_requests/policy/setting"
        api_url = self.prefix + postfix
        respon = requests.get(api_url, headers=self.headers, verify=False)
        respon_obj = json.loads(respon.content.decode())
        for per in respon_obj[0]["required_reviewers"]:
            required_reviewers.append(per["name"])
        return required_reviewers


if __name__ == "__main__":
    github_api = GitHub()
    projects_list = github_api.get_all_projectid(464820)
    print(len(projects_list))
